package com.tuanzi.loan.business.service.businesssystem.impl;

import com.tuanzi.loan.business.entity.businesssystem.BusinessIncome;
import com.tuanzi.loan.business.entity.businesssystem.BusinessMain;
import com.tuanzi.loan.business.entity.businesssystem.BusinessProduct;
import com.tuanzi.loan.business.repository.businesssystem.BusinessIncomeRepository;
import com.tuanzi.loan.business.repository.businesssystem.BusinessMainRepository;
import com.tuanzi.loan.business.repository.businesssystem.BusinessProductRepository;
import com.tuanzi.loan.business.repository.statistics.custom.ActivityRegisterRepositoryCustom;
import com.tuanzi.loan.business.repository.statistics.custom.StatCheckInCustomRepository;
import com.tuanzi.loan.business.service.businesssystem.BusinessIncomeService;
import com.tuanzi.loan.core.aspect.Debug;
import com.tuanzi.loan.core.repository.JPAAuditRepository;
import com.tuanzi.loan.core.service.BaseAuditServiceImpl;
import com.tuanzi.loan.core.vo.PageSearcher;
import com.tuanzi.loan.vo.request.businesssystem.BusinessIncomeRequest;
import com.tuanzi.loan.vo.response.businesssystem.BusinessIncomeResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.retry.RetryException;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

@Debug
@Service
@Transactional
@Retryable(value = { RetryException.class })
public class BusinessIncomeServiceImpl extends BaseAuditServiceImpl<BusinessIncome, Long> implements BusinessIncomeService {
	@Autowired
	private BusinessIncomeRepository settlementIncomeRepository;

	@Autowired
	private BusinessMainRepository settlementCompanyRepository;

	@Autowired
	private ActivityRegisterRepositoryCustom activityRegisterRepository;

	@Autowired
	private StatCheckInCustomRepository statCheckInRepository;

	@Autowired
	private BusinessProductRepository productRepository;

	private ReentrantLock lock = new ReentrantLock();

	@Override
	public Page<BusinessIncomeResponse> list(PageSearcher<BusinessIncomeRequest> pageSearcher) {
		return settlementIncomeRepository.list(pageSearcher.getSearchCondition(), pageSearcher.getPageable());
	}

	@Override
	public void onSave(BusinessIncome settlementIncome) {
		Long settlementIncomeId = settlementIncome.getId();
		Integer loginRecord = activityRegisterRepository.getLoginRecord(settlementIncome.getSettlementTime(), settlementIncome.getChannelId().toString());
		// 获得count、app和h5注册数，扣量后的
		if ((settlementIncome.getPayMode() == 1 || settlementIncome.getPayMode() == 2) && settlementIncome.getCount() == null) {
			Integer uv = activityRegisterRepository.getUv(settlementIncome.getSettlementTime(), settlementIncome.getChannelId().toString(), settlementIncome.getPayMode());
			if (uv <= 0) {
				settlementIncome.setCount(0);
			} else {
				settlementIncome.setCount(uv);
			}
			settlementIncome.setIncomeAmount(uv * settlementIncome.getPricePay());
		}
		// 按登录数模式结算
		if (settlementIncome.getPayMode() == 7 && settlementIncome.getCount() == null) {
			settlementIncome.setCount(loginRecord);
			settlementIncome.setIncomeAmount(loginRecord * settlementIncome.getPricePay());
		}
		// 各渠道的参与uv截流前的
		settlementIncome.setBeforeRealCost(statCheckInRepository.getUv(settlementIncome.getSettlementTime(), settlementIncome.getChannelId()));

		// 登录数
		settlementIncome.setLoginCount(loginRecord);

		// 实际注册
		Integer payMode = settlementIncome.getPayMode();
		Integer count = null;
		if (payMode != 6) {
			count = activityRegisterRepository.getRealCount(settlementIncome.getSettlementTime(), settlementIncome.getChannelId().toString(), payMode);
		} else {
			// 参考的熊花花实现
			// count = statUserCoreRepositoryCustom.getCPD(settlementIncome.getSettlementTime(), settlementIncome.getChannelId());
			// 菠萝贷没有截流前的注册数据，待商榷。
			count = 0;
		}
		if (count <= 0) {
			settlementIncome.setRealCost(0);
		} else {
			settlementIncome.setRealCost(count);
		}

		// 更新主体的消耗金额
		Double incomeAmount = null;
		Double expendAmount = null;
		BusinessMain company = null;
		Double lastIncomeAmount = settlementIncome.getLastIncomeAmount();// 最后一次消耗金额
		try {
			lock.lock();
			BusinessProduct one = productRepository.findByChannelId(settlementIncome.getChannelId());
			company = settlementCompanyRepository.findOne(one.getCompanyId().longValue());
			expendAmount = company.getExpendAmount();
			incomeAmount = settlementIncome.getIncomeAmount();
			if (expendAmount == null) {
				company.setExpendAmount(incomeAmount);
			} else {
				if (settlementIncomeId == null) { // 如果是添加消耗记录，公司的消耗金额 = 原始消耗金额+结算金额
					company.setExpendAmount(expendAmount + incomeAmount);
				} else {// 如果是修改消耗记录 ， 公司的消耗 金额 = 原始消耗金额 - 最后一次结算金额 + 要更新的结算金额
					if (lastIncomeAmount != incomeAmount) {// 上次消耗金额和这次消耗金额不同才更新
						company.setExpendAmount(expendAmount - lastIncomeAmount + incomeAmount);
					}
				}
			}
			settlementCompanyRepository.save(company);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}

		// 保存消耗记录
		settlementIncome.setLastIncomeAmount(incomeAmount);
		settlementIncomeRepository.save(settlementIncome);

	}

	@Override
	public void autoCount(Date startTime, Date endTime) {
		List<Date> betweenDates = getBetweenDates(startTime, endTime);
		List<BusinessProduct> autoProductList = productRepository.getAutoProductList();
		for (BusinessProduct product : autoProductList) {
			for (Date date : betweenDates) {
				BusinessIncome income = new BusinessIncome();
				income.setChannelId(Long.valueOf(product.getChannelId()));
				income.setSettlementTime(date);
				income.setBelongAppId(product.getBelongAppId());
				income.setChannelType(product.getChannelType());
				income.setPayType(product.getPayType());
				income.setPricePay(product.getPricePay());
				income.setPayMode(product.getPayMode());
				Integer uv = activityRegisterRepository.getUv(date, income.getChannelId().toString(), product.getPayMode());
				if(uv <= 0)
					continue;
				income.setBeforeRealCost(statCheckInRepository.getUv(date, income.getChannelId()));
				income.setCount(uv <= 0 ? 0 : uv);
				income.setIncomeAmount(income.getPricePay() * income.getCount());
				Integer count = activityRegisterRepository.getRealCount(income.getSettlementTime(), income.getChannelId().toString(), income.getPayMode());
				income.setRealCost(count <= 0 ? 0 : count);
				income.setChannelMain(product.getCompanyId());
				// 登录数
				income.setLoginCount(activityRegisterRepository.getLoginRecord(income.getSettlementTime(), income.getChannelId().toString()));

				// 更新主体的消耗金额
				Double incomeAmount = null;
				Double expendAmount = null;
				BusinessMain company = null;
				try {
					lock.lock();
					BusinessProduct one = productRepository.findByChannelId(income.getChannelId());
					company = settlementCompanyRepository.findOne(one.getCompanyId().longValue());
					expendAmount = company.getExpendAmount();
					incomeAmount = income.getIncomeAmount();
					if (expendAmount == null) {
						company.setExpendAmount(incomeAmount);
					} else {
						company.setExpendAmount(expendAmount + incomeAmount);
					}
					settlementCompanyRepository.save(company);
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					lock.unlock();
				}

				// 保存消耗记录
				income.setLastIncomeAmount(incomeAmount);

				settlementIncomeRepository.save(income);
			}
		}

	}

	@Override
	public Double getAllIncome(BusinessIncomeRequest $) {
		return settlementIncomeRepository.getAllIncome($);
	}

	@Override
	protected JPAAuditRepository<BusinessIncome, Long> getRepository() {
		return settlementIncomeRepository;
	}

	private List<Date> getBetweenDates(Date start, Date end) {
		List<Date> result = new ArrayList<Date>();
		Calendar tempStart = Calendar.getInstance();
		tempStart.setTime(start);

		Calendar tempEnd = Calendar.getInstance();
		tempEnd.setTime(end);
		while (!tempStart.after(tempEnd)) {
			result.add(tempStart.getTime());
			tempStart.add(Calendar.DAY_OF_YEAR, 1);
		}
		return result;
	}
}
